package com.sms.core.service;

import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;

import org.springframework.stereotype.Component;

/**
 * @desc 异常记录，方便在管理员后台查阅
 * @author wjw
 * @time 2017年11月16日下午3:31:05
 */
@Component
public class ExceptionProcesser {
    
    /** 只记录最近的异常个数 */
    private static final int SIZE = 32;
    
    /** 如果异常个数增大到阈值个数时启用删除 */
    private static final int SIZE_LIMIT = SIZE + SIZE / 2;
    
    /** 记录队列 */
    private ArrayBlockingQueue<ExceptionRecorder> queue = new ArrayBlockingQueue<>(SIZE * 2);
    
    public void addException(Exception exception) {
        addException(null, exception);
    }
    
    public void addException(String smsId, Exception exception) {
        if (exception == null) {
            return;
        }
        if (queue.size() >= SIZE_LIMIT) {
            while (queue.size() >= SIZE) {
                queue.poll();
            }
        }
        queue.offer(new ExceptionRecorder(smsId, exception));
    }
    
    public Collection<ExceptionRecorder> getExceptions() {
        return Collections.unmodifiableCollection(queue);
    }
    
    public static class ExceptionRecorder implements Serializable {
        
        private static final long serialVersionUID = -8356435791506376454L;
        
        /** 异常的时间 */
        private Date date;
        /** 异常堆栈 */
        private String stackTrace;
        /** 异常堆栈 */
        private String message;
        /** 短信ID */
        private String smsId;
        
        /**
         * 构造函数
         * @param exception xx
         */
        public ExceptionRecorder(Exception exception) {
            this(null, exception);
        }
        
        /**
         * 构造函数
         * @param smsId
         * @param exception
         */
        public ExceptionRecorder(String smsId, Exception exception) {
            this.smsId = smsId;
            this.date = new Date();
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            exception.printStackTrace(pw);
            this.message = exception.getMessage();
            this.stackTrace = sw.toString();
        }
        
        public Date getDate() {
            return date;
        }
        public String getStackTrace() {
            return stackTrace;
        }
        public String getMessage() {
            return message;
        }
        public String getSmsId() {
            return smsId;
        }
    }
}
